#pragma once
#include <cstdio>
#include <iostream>
#include <string>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdarg.h>
#include <pthread.h>
#include <fstream>
#include "LockGuard.hpp"

using namespace std;

bool gIsSave = false; // 是否要写到文件里
const string logname = "log.txt";

// 日志等级
enum Level
{
    DEBUG = 0, // 测试
    INFO,      // 正常
    WARNING,   // 警告
    ERROR,     // 错误
    FATAL      // 致命错误
};

// 写到文件里
void SaveFile(const string &filename, const string &message)
{
    ofstream out(filename, ios::app);
    if (!out.is_open())
    {
        return;
    }
    out << message;
    out.close();
}

string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";
    case INFO:
        return "Info";
    case WARNING:
        return "warning";
    case ERROR:
        return "Error";
    case FATAL:
        return "Fatal";
    default:
        return "Unkown";
    }
}

string GetTimeString()
{
    time_t curr_time = time(nullptr);
    struct tm *format_time = localtime(&curr_time);
    if (format_time == nullptr)
        return "None";
    char time_buffer[1024];
    snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
             format_time->tm_year + 1900,
             format_time->tm_mon + 1,
             format_time->tm_mday,
             format_time->tm_hour,
             format_time->tm_min,
             format_time->tm_sec);
    return time_buffer;
}

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// 日志的格式：
//    日志等级 时间 代码所在的文件名/行数 日志的内容

void LogMessage(string filename, int line, bool issave, int level, const char *format, ...) // 自由控制参数
{
    string levelstr = LevelToString(level);
    string timestr = GetTimeString();
    pid_t selfid = getpid();

    char buffer[1024];
    va_list arg;
    va_start(arg, format);
    vsnprintf(buffer, sizeof(buffer), format, arg);
    va_end(arg);

    string message;
    message = "[" + timestr + "]" + "[" + levelstr + "]" + "[pid: " + to_string(selfid) + "]" + "[" + filename + "]" + "[" + to_string(line) + "] " + buffer + "\n";
    LockGuard lockguard(&lock); // 锁——构造加锁 析构解锁
    if (!issave)
    {
        cout << "[" << timestr << "]"
             << "[" << levelstr << "]"
             << "[pid: " << selfid << "]"
             << "[" << filename << "]"
             << "[" << line << "] "
             << buffer << endl;
    }
    else
    {
        SaveFile(logname, message);
    }

    // cout << levelstr << ":" << timestr << ":" << filename <<":"<<line<<":"<<buffer<< endl;
}

#define LOG(level, format, ...)                                                \
    do                                                                         \
    {                                                                          \
        LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \
    } while (0)

// 往文件里写
#define EnableFile()    \
    do                  \
    {                   \
        gIsSave = true; \
    } while (0)
// 往显示器上写
#define EnableScreen()   \
    do                   \
    {                    \
        gIsSave = false; \
    } while (0)
